<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="absolute" frameRate="60" 
    addedToStage="init()" enterFrame="onEnter()">
    <mx:Script>
        <![CDATA[
        /**
         * 【 BetweenAS3 を使ってトゥイーンのシーク制御 】
		 * スライダーをドラッグ＆ドロップで複合トゥイーンをシークできます。
		 * 
         * 技術的な解説は次の記事で 
         * http://clockmaker.jp/blog/2009/07/betweenas3/
         */
        import flash.display.*;
        import flash.events.*;
        import org.papervision3d.materials.*;
        import org.papervision3d.materials.special.CompositeMaterial;
        import org.papervision3d.materials.utils.MaterialsList;
        import org.papervision3d.objects.primitives.*;
        import org.papervision3d.view.BasicView;
        import org.libspark.betweenas3.BetweenAS3;
        import org.libspark.betweenas3.tweens.ITween;
        import org.libspark.betweenas3.easing.*;
    
        static private const OBJ_NUM :int = 20; // オブジェクトの個数
        public var rot:Number = 0; // カメラの円運動用
        private var world:BasicView = new BasicView(); // PV3D
        private var baseTween:ITween; // ベースのトゥイーン生成
        
        public function init():void {
            // Flashの初期設定
            stage.quality = StageQuality.MEDIUM;
            
            // pv3dの初期設定
            container.addChild(world);
            world.viewport.opaqueBackground = 0x0;
            world.camera.focus = 250;
            
            // カメラの動きをTweenで作る
            baseTween = BetweenAS3.parallel(
                BetweenAS3.tween(this, { rot:0 }, { rot:135 }, 7, Cubic.easeInOut),
                BetweenAS3.tween(world.camera, { y:400, zoom:4 }, { y:-100, zoom:1 }, 6, Cubic.easeInOut)
            );
            
            for (var i:int = 0; i < OBJ_NUM; i++) {
                // キューブ
                var mt:CompositeMaterial = new CompositeMaterial();
                mt.addMaterial( new ColorMaterial(0x0, 0.5) );
                mt.addMaterial( new WireframeMaterial(0xFF0000) );
                var cube:Cube = world.scene.addChild(new Cube(new MaterialsList( { all:mt } ), 100, 100, 100)) as Cube;
                
                // 座標
                cube.x = 1500 * Math.random() - 750;
                cube.z = 1500 * Math.random() - 750;
                
                // 秒数
                var sec:Number = 2 * Math.random() + 3;
                
                // 基礎となるTweenを作る
                baseTween = BetweenAS3.parallel(
                    BetweenAS3.tween(cube, { y:0 }, { y:2000 }, sec, Bounce.easeOut),
                    baseTween
                );
            }
            
            baseTween.stopOnComplete = false; // ループ設定
            baseTween.play(); // 再生
            
            // レンダリング関係
            world.startRendering();
            
            // ついでに地面
            var earth:Plane = world.scene.addChild(new Plane(new WireframeMaterial(0x666666), 5000, 5000, 15, 15)) as Plane;
            earth.rotationX = 90;
        }
        
        // エンターフレーム
        private function onEnter(event:Event = null):void {
            // スライダーとトゥイーンの値を同期
            if(baseTween) slider.value = baseTween.position / baseTween.duration;
            
            // カメラの回転(BetweenAS3で制御するため)
            world.camera.x = 1000 * Math.cos(rot * Math.PI / 180);
            world.camera.z = 1000 * Math.sin(rot * Math.PI / 180);
        }
        
        // スライダーを動かしたとき
        private function onChange():void {
            // トゥイーンをスライダーで制御 ( トゥイーンの時間 × スライダーの百分率 )
            baseTween.gotoAndStop(baseTween.duration * slider.value);
        }
        
        // 再生ボタンをクリックしたとき
        private function onClick():void {
            // 再生と停止を切り替え
            baseTween.isPlaying ? baseTween.stop() : baseTween.play();
        }
        ]]>
    </mx:Script>
    <mx:UIComponent id="container" width="100%" height="100%" />
    <mx:Button label="Play/Stop" click="onClick()" x="180" y="400" />
    <mx:HSlider id="slider" change="onChange()" minimum="0" maximum="1" liveDragging="true" x="140" y="430" />
</mx:Application>
